// https://zhuanlan.zhihu.com/p/183801144
/**
 promise 有三个状态：pending，fulfilled，or rejected；「规范 Promise/A+ 2.1」
 new promise时， 需要传递一个executor()执行器，执行器立即执行；
 executor接受两个参数，分别是resolve和reject；
 promise 的默认状态是 pending；
 promise 有一个value保存成功状态的值，可以是undefined/thenable/promise；「规范 Promise/A+ 1.3」
 promise 有一个reason保存失败状态的值；「规范 Promise/A+ 1.5」
 promise 只能从pending到rejected, 或者从pending到fulfilled，状态一旦确认，就不会再改变；
 promise 必须有一个then方法，then 接收两个参数，分别是 promise 成功的回调 onFulfilled, 和 promise 失败的回调 onRejected；「规范 Promise/A+ 2.2」
 如果调用 then 时，promise 已经成功，则执行onFulfilled，参数是promise的value；
 如果调用 then 时，promise 已经失败，那么执行onRejected, 参数是promise的reason；
 如果 then 中抛出了异常，那么就会把这个异常作为参数，传递给下一个 then 的失败的回调onRejected；
 */

/**
 // 三个状态：PENDING、FULFILLED、REJECTED
 const PENDING = 'PENDING';
 const FULFILLED = 'FULFILLED';
 const REJECTED = 'REJECTED';
 class myPromise {
 	constructor(executor) {
 		this.status = PENDING;
 		this.value = undefined;
 		this.reason = undefined;
 		// 存放成功的回调
 		this.onResolvedCallbacks = [];
 		// 存放失败的回调
 		this.onRejectedCallbacks = [];
 		let resolve = (value) => {
 			if (this.status === PENDING) {
 				this.status = FULFILLED;
 				this.value = value;
 				// 依次将对应的函数执行
 				this.onResolvedCallbacks.forEach(fn => fn());
 			}
 		}
 		let reject = (reason) => {
 			if (this.status === PENDING) {
 				this.status = REJECTED;
 				this.reason = reason;
 				// 依次将对应的函数执行
 				this.onRejectedCallbacks.forEach(fn => fn());
 			}
 		}
 		try {
 			executor(resolve, reject)
 		} catch (error) {
 			reject(error)
 		}
 	}
 	then(onFulfilled, onRejected) {
 		if (this.status === FULFILLED) {
 			onFulfilled(this.value)
 		}
 		if (this.status === REJECTED) {
 			onRejected(this.reason)
 		}
 		if (this.status === PENDING) {
			// 发布订阅模式，收集依赖 -> 触发通知
 			// 如果promise的状态是 pending，需要将 onFulfilled 和 onRejected 函数存放起来，等待状态确定后，再依次将对应的函数执行
 			this.onResolvedCallbacks.push(() => {
 				onFulfilled(this.value)
 			});
 			// 如果promise的状态是 pending，需要将 onFulfilled 和 onRejected 函数存放起来，等待状态确定后，再依次将对应的函数执行
 			this.onRejectedCallbacks.push(() => {
 				onRejected(this.reason);
 			})
 		}
 	}
 } 
 */

// then 链式调用 值穿透
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
const resolvePromise = (promise2, x, resolve, reject) => {
	// 自己等待自己完成是错误的实现，用一个类型错误，结束掉 promise  Promise/A+ 2.3.1
	if (promise2 === x) {
		return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
	}
	// Promise/A+ 2.3.3.3.3 只能调用一次
	let called;
	// 后续的条件要严格判断 保证代码能和别的库一起使用
	if ((typeof x === 'object' && x != null) || typeof x === 'function') {
		try {
			// 为了判断 resolve 过的就不用再 reject 了（比如 reject 和 resolve 同时调用的时候）  Promise/A+ 2.3.3.1
			let then = x.then;
			if (typeof then === 'function') {
				// 不要写成 x.then，直接 then.call 就可以了 因为 x.then 会再次取值，Object.defineProperty  Promise/A+ 2.3.3.3
				then.call(x, y => { // 根据 promise 的状态决定是成功还是失败
					if (called) return;
					called = true;
					// 递归解析的过程（因为可能 promise 中还有 promise） Promise/A+ 2.3.3.3.1
					resolvePromise(promise2, y, resolve, reject);
				}, r => {
					// 只要失败就失败 Promise/A+ 2.3.3.3.2
					if (called) return;
					called = true;
					reject(r);
				});
			} else {
				// 如果 x.then 是个普通值就直接返回 resolve 作为结果  Promise/A+ 2.3.3.4
				resolve(x);
			}
		} catch (e) {
			// Promise/A+ 2.3.3.2
			if (called) return;
			called = true;
			reject(e)
		}
	} else {
		// 如果 x 是个普通值就直接返回 resolve 作为结果  Promise/A+ 2.3.4  
		resolve(x)
	}
}
class myPromise {
	constructor(executor) {
		this.status = PENDING;
		this.value = undefined;
		this.reason = undefined;
		this.onResolvedCallbacks = [];
		this.onRejectedCallbacks = [];
		let resolve = (value) => {
			if (this.status === PENDING) {
				this.status = FULFILLED;
				this.value = value;
				this.onResolvedCallbacks.forEach(fn => fn());
			}
		}
		let reject = (reason) => {
			if (this.status === PENDING) {
				this.status = REJECTED;
				this.reason = reason;
				this.onRejectedCallbacks.forEach(fn => fn());
			}
		}
		try {
			executor(resolve, reject)
		} catch (error) {
			reject(error)
		}
	}
	then(onFulfilled, onRejected) {
		// 解决 onFufilled，onRejected 没有传值的问题
		// Promise/A+ 2.2.1 / Promise/A+ 2.2.5 / Promise/A+ 2.2.7.3 / Promise/A+ 2.2.7.4
		onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
		// 因为错误的值要让后面访问到，所以这里也要跑出个错误，不然会在之后 then 的 resolve 中捕获
		onRejected = typeof onRejected === 'function' ? onRejected : err => {
			throw err
		};
		// 每次调用 then 都返回一个新的 promise  Promise/A+ 2.2.7
		let promise2 = new myPromise((resolve, reject) => {
			if (this.status === FULFILLED) {
				//Promise/A+ 2.2.2
				//Promise/A+ 2.2.4 --- setTimeout
				setTimeout(() => {
					try {
						//Promise/A+ 2.2.7.1
						let x = onFulfilled(this.value);
						// x可能是一个proimise
						resolvePromise(promise2, x, resolve, reject);
					} catch (e) {
						//Promise/A+ 2.2.7.2
						reject(e)
					}
				}, 0);
			}
			if (this.status === REJECTED) {
				//Promise/A+ 2.2.3
				setTimeout(() => {
					try {
						let x = onRejected(this.reason);
						resolvePromise(promise2, x, resolve, reject);
					} catch (e) {
						reject(e)
					}
				}, 0);
			}
			if (this.status === PENDING) {
				this.onResolvedCallbacks.push(() => {
					setTimeout(() => {
						try {
							let x = onFulfilled(this.value);
							resolvePromise(promise2, x, resolve, reject);
						} catch (e) {
							reject(e)
						}
					}, 0);
				});
				this.onRejectedCallbacks.push(() => {
					setTimeout(() => {
						try {
							let x = onRejected(this.reason);
							resolvePromise(promise2, x, resolve, reject)
						} catch (e) {
							reject(e)
						}
					}, 0);
				});
			}
		});
		return promise2;
	}
}

myPromise.defer = myPromise.deferred = function() {
	let dfd = {};
	dfd.myPromise = new myPromise((resolve, reject) => {
		dfd.resolve = resolve;
		dfd.reject = reject;
	})
	return dfd;
}